<template>
  <div
    :class="animate"
    :style="{ height: height, width: width }"
    :id="chartOption.bindingDiv"
    ref="chartDiv"
  ></div>
</template>

<script>
import echarts from "echarts";
require("echarts/theme/macarons"); // echarts theme
import resize from "@/views/dashboard/mixins/resize";

import "../../animate/animate.css";

import { parseQueryString, fIsUrL } from "../../util/urlUtil";
import { linkChart } from "../../util/LinkageChart";
import { chartApiBar, remoteChartApi,chartBIanalysis  } from "@/api/tool/datav/chartApi";

import { addOption } from "../../codegen/codegen";

import { pieBIanalysis } from "@/api/tool/datav/chartBI/chartPieBI";
import { getFormsource } from "@/api/tool/datav/formsource";

const animationDuration = 6000;
import VueEvent from "@/views/tool/datav/VueEvent";
import { websocketCommand } from "../../util/websocket.js";

export default {
  mixins: [resize],

  props: {
    className: {
      type: String,
      default: "chart"
    },
    width: {
      type: String,
      default: "100%"
    },
    height: {
      type: String,
      default: "100%"
    },
    chartOption: {
      type: Object
    },
    drawingList: {
      type: Array
    }
  },
  data() {
    return {
      chart: null,
      //dataOption: this.chartOption,
      timer: "",
      wsObj: null,
      wsFlag: false,
      wsTimer: "",
      wsValue: null,
      animate: this.className
    };
  },
  watch: {
    width() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    height() {
      this.$nextTick(() => {
        this.chart.resize();
      });
    },
    chartOption: {
      deep: true,
      handler(newVal, oldValue) {
        this.setOptions(JSON.parse(JSON.stringify(newVal)));
      }
    },
    "chartOption.theme": {
      handler() {
        this.chart.dispose();
        this.chart = null;
        this.initChart();
      }
    },
    "chartOption.timeout": {
      handler() {
        this.chart.dispose();
        this.chart = null;
        this.initChart();
      }
    },
    "chartOption.dataSourceType": {
      handler(value) {
        //切换数据源重新连接
        if (value !== "websocket") {
          this.wsFlag = false;
          //每次切换数据源恢复原来动画
          this.animate = this.className;
        }
        if (value !== "url") {
          clearTimeout(this.timer);
        } 
      }
    },
    "chartOption.interfaceKey": {
      handler(newValue, oldValue) {
        //初始化不创建连接，改变接口地址重新创建
        if (oldValue !== undefined) {
          this.wsValue = null;
          this.closeWs();
          this.createWs();
          this.animate = this.className;
        }
      }
    },
    wsFlag: {
      handler(value) {
        if (!value) {
          this.wsValue = null;
          this.closeWs();
        }
      }
    },
    className: {
      handler(value) {
        this.animate = value;
      }
    }
  },
  mounted() {
    //this.$nextTick(() => {
    this.initChart();
    //});
  },
  beforeDestroy() {
    if (!this.chart) {
      return;
    }
    this.chart.dispose();
    this.chart = null;
    clearTimeout(this.timer);
    if (this.wsFlag) {
      this.closeWs();
    }
  },
  methods: {
    initChart() {
      echarts.registerTheme("customTheme", this.chartOption.theme);
      this.chart = echarts.init(
        document.getElementById(this.chartOption.bindingDiv),
        "customTheme"
      );
      
      //判断是否开启定时器，当是访问url接口时候并且timeout不为0时候开启定时器
      if (this.timer != "") {
        clearTimeout(this.timer);
      }
      if (
        (this.chartOption.dataSourceType == 'url' || this.chartOption.dataSourceType == 'database') &&
        this.chartOption.timeout > 0
      ) {
        let timerTask = () => {
          this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
          this.timer = setTimeout(() => {
            timerTask();
          }, this.chartOption.timeout);
        };

        timerTask();
      }else{
        this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    setOptions: async function(dataOption) {
      // console.log("remote=>", dataOption.remote);
      //初始化数据，判断数据源
      //如果不是静态数据就调用接口给staticDataValue赋值
      if (dataOption.dataSourceType == "url") {
        let paramJson = parseQueryString(dataOption.requestParameters);
        //let interfaceURL = 'http://localhost:8088/chart/api/bar';
        let interfaceURL = dataOption.interfaceURL;
        dataOption.staticDataValue = await chartApiBar(
          dataOption.requestMethod,
          interfaceURL,
          paramJson,
          dataOption.token
        );
        //先判断输入的url是否合法
        // if(fIsUrL(dataOption.interfaceURL)) {
        //   try {
        //     //ajax请求
        //     var paramJson = parseQueryString(dataOption.requestParameters);
        //   } catch (error) {

        //   }
        // }

        //console.log(paramJson);
      } else if (dataOption.dataSourceType == "database") {
        if (
          dataOption.database.executeSql != undefined &&
          dataOption.database.executeSql != ""
        ) {
          let result = [];
          if(dataOption.database.sqlType != 'custom'){
          
            result = await pieBIanalysis(dataOption.database);
          }else{
            result = await chartBIanalysis(dataOption.database);
          }
          if (result.code == 200) {
            dataOption.staticDataValue = result.data;
            //console.log(dataOption.staticDataValue);
          } else {
            alert("操作数据库错误");
          }
        }
      } else if (dataOption.dataSourceType == "form") {
        if (dataOption.formSource != undefined) {
          let response = await getFormsource(dataOption.formSource.id);
          dataOption.staticDataValue = JSON.parse(response.data.formData);
        }
      } else if (dataOption.dataSourceType == "websocket") {
        if (
          dataOption.interfaceKey != undefined &&
          dataOption.interfaceKey != ""
        ) {
          if (!this.wsFlag) {
            this.wsFlag = true;
            this.wsValue = null;
            this.createWs();
          }
          if (this.wsValue != null) {
            dataOption.staticDataValue = this.wsValue;
          }
        }
      }

      if (dataOption.animate != null) {
        //添加动画样式
        //animateUtil.addAnimate(dataOption.bindingDiv, dataOption.animate);
      }

      var data = [];
      if (dataOption.isRoseType == true) {
        dataOption.series[0].roseType = "area";
      } else {
        dataOption.series[0].roseType = false;
      }
      if (dataOption.isRing == true) {
        dataOption.series[0].radius = [
          dataOption.innerRadius,
          dataOption.outerRadius
        ];
      } else {
        dataOption.series[0].radius = "55%";
      }
      if (dataOption.isFan == true) {
        dataOption.series[0].clockwise = false;
        if (dataOption.isRoseType == true) {
          for (let i = 0; i < dataOption.staticDataValue.length; i++) {
            data.push(dataOption.staticDataValue[i]);
          }
          var all =
            (dataOption.staticDataValue.length * 360) /
            (dataOption.endAngle - dataOption.startAngle);
          var add = all - dataOption.staticDataValue.length;
          for (let i = 0; i < add; i++) {
            var thedata = {
              value: 0,
              name: "",
              itemStyle: { color: "rgba(255, 0, 0, 0)" },
              tooltip: { show: false }
            };
            data.push(thedata);
          }
        } else {
          var sum = 0;
          for (let i = 0; i < dataOption.staticDataValue.length; i++) {
            data.push(dataOption.staticDataValue[i]);
            sum += dataOption.staticDataValue[i].value;
          }
          let add =
            (sum * 360) / (dataOption.endAngle - dataOption.startAngle) - sum;
          var thedata = {
            value: add,
            name: "",
            itemStyle: { color: "rgba(255,0,0,0)" },
            tooltip: { show: false }
          };
          data.push(thedata);
        }
      } else {
        data = dataOption.staticDataValue;
      }
      dataOption.series[0].startAngle = dataOption.startAngle;
      dataOption.series[0].data = data;
      if (dataOption.centerX != undefined && dataOption.centerY != undefined) {
        dataOption.series[0].center = [
          dataOption.centerX + "%",
          dataOption.centerY + "%"
        ];
      }

      //引导线设置
      if (dataOption.series[0].label.show == true) {
        //显示引导线时，执行以下方法
        let labelLine = {
          length:
            dataOption.labelLineLength == undefined
              ? 15
              : dataOption.labelLineLength, //第一段引导线长度
          length2:
            dataOption.labelLineLength2 == undefined
              ? 10
              : dataOption.labelLineLength2, //第二段引导线长度
          lineStyle: {
            width: dataOption.labelLineWidth //引导线宽度
          }
        };
        dataOption.series[0].labelLine = labelLine;
      }
      let formatter = []; //标签显示内容
      if (dataOption.labelFormatter == undefined) {
        dataOption.labelFormatter = ["类别名称"];
      }
      for (let item of dataOption.labelFormatter) {
        if (item == "类别名称") {
          formatter[0] = "{b} ";
        }
        if (item == "数值") {
          formatter[1] = "{c}" + dataOption.formatterSuffix;
        }
        if (item == "百分比") {
          formatter[2] = "({d}%)";
        }
      }
      let formatterStr = "";
      for (let item of formatter) {
        if (item != undefined) {
          formatterStr += item;
        }
      }
      //标签设置
      dataOption.series[0].label.formatter = formatterStr;
      dataOption.series[0].label.fontSize = dataOption.labelFontSize;

      //图例设置
      let legends = [];
      let formatterAgrs = {};
      dataOption.legend.height = "80%"; //图例显示区域的高度
      dataOption.legend.itemGap = dataOption.legendItemGapY || 10; //图例垂直方向间隔，默认10
      dataOption.legend.textStyle.fontSize = dataOption.legendFontSize; //图例字号
      dataOption.legend.textStyle.color = dataOption.legendFontColor; //图例字号

      if (dataOption.showPercentage == true) {
        let rich = {
          // 通过富文本rich给每个项设置样式，下面的one、two可以理解为"每一列"的样式
          one: {
            // 设置类别这一列的样式
            width: dataOption.textWidth,
            color: dataOption.legendFontColor,
            fontSize: dataOption.legendFontSize
          },
          two: {
            // 设置百分比这一列的样式
            width: 50,
            color: dataOption.legendFontColor,
            fontSize: dataOption.legendFontSize
          }
        };
        dataOption.legend.textStyle.rich = rich;

        formatterAgrs = {
          formatter: name => {
            // formatter格式化函数动态呈现数据
            var data = dataOption.series[0].data;
            var total = 0; // 用于计算总数
            var target; // 遍历拿到数据
            for (var i = 0; i < data.length; i++) {
              total += data[i].value;
              if (data[i].name == name) {
                target = data[i].value;
              }
            }
            let v = ((target / total) * 100).toFixed(1);
            return `{one|${name}}  {two|${v}%}`;
            //     富文本第一列样式应用    富文本第二列样式应用
          }
        };
      }

      let colNumber = dataOption.legendCols || 1; //选择图例分布的列数，默认1
      let legendCols = []; //用于装载每一列图例显示的标签
      let items = dataOption.series[0].data; // 饼图的数据

      for (let i = 0; i < colNumber; i++) {
        let legendData = [];
        let k = 0;
        for (let j = i; j < items.length; j += colNumber) {
          //以列数为步长
          legendData[k] = items[j]["name"];
          k++;
        }
        legendCols[i] = legendData;
      }
      for (let i = 0; i < legendCols.length; i++) {
        let legendTemp = JSON.parse(JSON.stringify(dataOption.legend));
        legendTemp.left =
          (dataOption.legendPositionLeft +
            (dataOption.legendItemGapX == undefined
              ? 0
              : dataOption.legendItemGapX) *
              i || 60) + "%"; //图例距离左边框 + 间隔的距离，默认60%
        legendTemp.top = (dataOption.legendPositionTop || 30) + "%"; //图例距离上边框距离，默认30%
        legendTemp.data = legendCols[i];
        legends.push(legendTemp);
      }

      //双环图 对series[0].data的处理，需要写在上面，否则创建newSeriesTemp，复制不到
      if (dataOption.isRing && dataOption.innerShadow) {
        let newSeriesTemp = JSON.parse(JSON.stringify(dataOption.series[0]));
        newSeriesTemp.emphasis = {};
        newSeriesTemp.radius = [
          dataOption.innerRadius * (1 - dataOption.innerRadiusScale),
          dataOption.innerRadius * 1.1
        ];
        let innerItemStyle = {
          opacity: dataOption.innerRadiusOpacity // 内圈 透明度
        };
        (newSeriesTemp.hoverAnimation = false),
          (newSeriesTemp.itemStyle = innerItemStyle);
        newSeriesTemp.label.show = false;
        dataOption.series.push(newSeriesTemp);
      }

      let option = {
        title: dataOption.title,
        tooltip: dataOption.tooltip,
        // legend: dataOption.legend,
        legend: legends,
        series: dataOption.series,
        formatter: formatterAgrs.formatter
        //, color: color
      };
      // console.log(option)
      //执行通用处理函数
      if(dataOption.customData != undefined && dataOption.customData != ""){
        try {
          option = (
          
            //里面为要处理的代码块
          eval(dataOption.customData) 
          
          )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
          );
        } catch (error) {
          console.log(error)
        }
       } 
        //交互组件配置
      if(dataOption.interactData != undefined && dataOption.interactData != ""){
          try {
              option = (        
              //里面为要处理的代码块
              eval(dataOption.interactData)             
            )(
            option,
            dataOption.staticDataValue,
            this.$refs.chartDiv
            );
          } catch (error) {
            console.log(error)
          }               
       }     
      this.chart.setOption(option, true);

      addOption(dataOption.bindingDiv, option);

      //开启图表联动
      if (dataOption.isLink == true) {
        this.chart.off("click");
        this.chart.on("click", params => {
          //设置参数
          let arrObject = {
            legendName: params.name,
            seriesName: params.seriesName,
            data: params.value
          };

          let arrs = JSON.stringify(arrObject);

          //获取绑定的图表
          let bindList = this.chartOption.bindList;

          if (bindList.length > 0) {
            linkChart(dataOption.arrName, arrs, bindList, this.drawingList);
          }
        });
      }
      // else{
      //   //关闭图表联动，取消echart点击事件
      //   this.chart.off('click');
      // }

      //开启图表下钻
      else if (dataOption.isDrillDown == true) {
        this.chart.off("click");
        this.chart.on("click", params => {
          //设置参数
          let arrObject = {
            legendName: params.name,
            seriesName: params.seriesName,
            data: params.value
          };

          let arrs = JSON.stringify(arrObject);

          //获取绑定的图表
          let drillDownChartOption = this.chartOption.drillDownChartOption;

          if (
            drillDownChartOption != undefined &&
            drillDownChartOption != null
          ) {
            this.$set(
              this.chartOption.drillDownChartOption.chartOption,
              "requestParameters",
              "drillParam=" + arrs
            );
            //发送下钻消息
            VueEvent.$emit(
              "drill_down_msg",
              this.chartOption.drillDownChartOption
            );
          }
        });
      } else {
        //关闭图表联动，取消echart点击事件
        this.chart.off("click");
      }

      //开启远程图表控制
      if (dataOption.isRemote == true) {
        if (dataOption.remote != undefined && dataOption.remote != null) {
          this.chart.off("click");
          this.chart.on("click", params => {
            //设置参数
            let arrObject = {
              legendName: params.name,
              seriesName: params.seriesName,
              data: params.value
            };

            let remoteData = { ...dataOption.remote };
            remoteData.query = arrObject;
            //调用接口
            remoteChartApi(remoteData);
          });
        }
      }
    },
    //  ws连接成功，后台返回的ws数据
    receiveMsg(e) {
      if (e.action == "chat") {
        // console.log('服务端推送',e);
        this.wsValue = JSON.parse(e.result);
        this.setOptions(JSON.parse(JSON.stringify(this.chartOption)));
      }
    },
    // 建立连接、发起ws请求，以心跳方式，向服务端发送数据
    createWs() {
      this.wsObj = new WebSocket(process.env.VUE_APP_WEBSOCKET);
      // 若为对象类型，以回调方式发送
      websocketCommand(
        this.wsObj,
        "create",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
    },
    // 断网重连，需要处理的逻辑
    reconnectWs() {
      if (this.wsObj) {
        console.log("%c websocket_reconnect", "color:blue");
        this.createWs();
      }
    },
    // 以回调方式向服务端发送(对象类型的)心跳
    sendHeartBeat() {
      if (this.wsTimer != "") {
        clearTimeout(this.wsTimer);
      }

      let wsTimerTask = () => {
        console.log("发送心跳", "ping");
        let obj = { action: "keep", key: this.chartOption.interfaceKey };
        this.wsObj.send(JSON.stringify(obj));
        this.wsTimer = setTimeout(() => {
          wsTimerTask();
        }, parseInt(process.env.VUE_APP_WEBSOCKET_TIMEOUT));
        this.wsWarning();
      };

      wsTimerTask();
    },
    wsWarning() {
      //如果断开连接则显示组件警告动画并清除计数器
      if (this.wsObj.readyState == 3) {
        this.animate = "warning";
        clearTimeout(this.wsTimer);
      }
    },
    closeWs() {
      clearTimeout(this.wsTimer);
      websocketCommand(
        this.wsObj,
        "close",
        5000,
        this.chartOption.interfaceKey,
        this.sendHeartBeat,
        this.receiveMsg,
        this.reconnectWs,
        this.wsWarning
      );
      this.wsObj = null;
    }
  }
};
</script>
